/**
 * @(#)UsuariosSeguridadManagerK.java Nov 10, 2006
 *
 * Copyright (c) 2005-2010 Psiqueware S.A. de C.V. All Rights Reserved.
 * This software is the proprietary information Psiqueware S.A. de C.V.
 * Use is subject to license terms.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * <br/>Usuario : AngelElectrico
 * <br/>Creaci&oacute;n: Nov 10, 2006 - 2:57:34 PM
 * <br/>
 * <br/>
 * <br/><t5>Cambios :</t5>
 * <br/><b>Fecha | Autor  |  Cambios</b>
 * <ul>
 * <li>Nov 10, 2006 | <a href = "mailto:AngelElectrico@PsiqueWare.com">Angel El&eacute;ctrico</a> | Creaci&oacute;n del Objeto.</li>
 * <li>Ene 23, 2007 | <a href = "mailto:AngelElectrico@PsiqueWare.com">Angel El&eacute;ctrico</a> | Se cambiar&oacute;n los mensajes de error por el nuevo formato UML.</li>
 * <li>Ene 25, 2007 | <a href = "mailto:AngelElectrico@PsiqueWare.com">Angel El&eacute;ctrico</a> | Se resolvi&oacute; el problema de la transaccionalidad truca por las excepciones de par&aacute;metros..</li>
 * </ul>
 */

package com.psiqueware.alheli.seguridad.manager;

import com.psiqueware.alheli.dao.EnlaceTransaccional;
import com.psiqueware.alheli.exception.NullArgumentException;
import com.psiqueware.alheli.logging.Logger;
import com.psiqueware.alheli.logging.LoggerFactory;
import com.psiqueware.alheli.manager.BaseManager;
import com.psiqueware.alheli.seguridad.*;
import com.psiqueware.alheli.seguridad.dao.*;
import com.psiqueware.alheli.seguridad.modelo.*;

import java.util.List;

/**
 * Controla la seguridad de los Usuario.
 * Manager Transaccional.
 * <br/>Paquete Original: com.psiqueware.basico.seguridad.manager
 * <br/>Nombre  Original: SeguridadUsuariosTManagerK
 * <br/>Oprima para ver : <a href="UsuariosSeguridadManagerK.java.html"><i>C&oacute;digo Fuente</i> </a>
 *
 * @author <a href="mailto:AngelElectrico@PsiqueWare.com">Angel El&eacute;ctrico</a>
 * @version Revision: 1.1 Nov 10, 2006 2:57:34 PM
 * @noinspection DuplicateStringLiteralInspection, CastToConcreteClass, ClassWithoutNoArgConstructor, ClassWithoutToString
 */
public final class UsuariosSeguridadManagerK extends BaseManager implements UsuariosSeguridadManager
{

    /**
     * Logger de clase para UsuariosSeguridadManagerK
     */
    private static final Logger s_log = LoggerFactory.getLogger(UsuariosSeguridadManagerK.class);

    /**
     * Nombre del {@link Rol} creado por defecto que contiene los {@link Permiso}s para la administraci&oacute;n de la seguridad.
     */
    private static String s_nombre_rol_universal = "<U>";

    /**
     * Devuelve el Nombre del {@link Rol} creado por defecto que contiene los {@link Permiso}s para la administraci&oacute;n de la seguridad.
     *
     * @return Valor de 's_nombre_rol_universal'.
     */
    public String getNombreRolUniversal()
    {
        return s_nombre_rol_universal;
    }

    /**
     * Establece el Nombre del {@link Rol} creado por defecto que contiene los {@link Permiso}s para la administraci&oacute;n de la seguridad.
     *
     * @param nombreRolUniversal Nuevo valor para 's_nombre_rol_universal'.
     */
    public synchronized void setNombreRolUniversal(final String nombreRolUniversal)
    {
        s_nombre_rol_universal = nombreRolUniversal;
    }

    /**
     * A&ntilde;ade un {@link UsuarioSeguridad} a la lista de control de estos, otorg&aacute;ndole todos los roles de una {@link Agrupacion} nueva.
     * Adem&aacute;s inicializa su credencial, en caso de que no tenga una asignada, le proporciona una con todos los permisos.
     *
     * @param usuarioSeguridad    Implementaci&oacute;n de esta interfaz a la que se le asignar&aacute; un usuario de seguridad.
     *                            Debe tener un identificador &uacute;nico, afin de poder distinguir un {@link UsuarioSeguridad} de otro. En caso de no
     *                            estar inicializado este par&aacute;metr&oacute; surgir&aacute; un {@link IllegalArgumentException}.
     * @param enlaceTransaccional enlace para hacer at&oacute;micas las transacciones.
     *
     * @throws com.psiqueware.alheli.seguridad.SeguridadException en caso de no poder completar la operaci&oacute;n.
     * @noinspection MethodWithMultipleLoops, FeatureEnvy, OverlyLongMethod, CastToConcreteClass
     */
    public void registrarUsuarioRaiz(UsuarioSeguridad usuarioSeguridad, final EnlaceTransaccional enlaceTransaccional) throws SeguridadException
    {
        try
        {
            if (null == usuarioSeguridad)
                throw new NullArgumentException("<error>El argumento 'usuarioSeguridad' no puede ser NULL.</error>");
            if (null == usuarioSeguridad.getId())
                throw new IllegalArgumentException("<error>El argumento 'usuarioSeguridad' deb&iacute;a encontrarse previamente persistido.</error>");

            //1.- Buscamos la credencialK y si no existe la creamos.
            CredencialK credencialK = buscaCredencialUsuario(usuarioSeguridad, enlaceTransaccional);
            if (null != credencialK)
            {
                String error = "<error><msg>El usuario ya se encontraba registrado.</msg><parameters>" + credencialK + "</parameters></error>";
                s_log.error(error);
                throw new SeguridadException(error);
            }

            credencialK = nuevaCredencialUsuarioSeguridad(usuarioSeguridad, enlaceTransaccional);

            //2.- Establecemos el AgrupacionK, debe ser nuevo para este super usuario.
            AgrupacionK agrupacion = nuevaAgrupacion(usuarioSeguridad, enlaceTransaccional);
            credencialK.setAgrupacion(agrupacion);

            //3.- A&ntilde;adimos los objetos
            usuarioSeguridad.setCredencial(credencialK);

            //4.- Iniciamos la Seguridad del Usuario
            iniciarSeguridadUsuario(usuarioSeguridad, enlaceTransaccional);

            //5 .- Salvamos la informaci&oacute;n
            SeguridadDAOFactory.findDAOCredencial(enlaceTransaccional).updateCredencial(credencialK, enlaceTransaccional);
        }
        catch (UsuarioNoRegistradoException e)
        {
            String error = "<error><msg>El UsuarioSeguridad no se pudo registrar correctamente.</msg><parametros>" + usuarioSeguridad + "</parametros></error>";
            s_log.error(error);
            s_log.error(e);
            enlaceTransaccional.rollBack();
            throw new SeguridadException(error, e);
        }
        catch (Exception e)
        {
            String error = "<error><msg>Error intentando registrar el SuperUsuario.</msg><parametros>" + usuarioSeguridad + "</parametros></error>";
            s_log.error(error);
            s_log.error(e);
            enlaceTransaccional.rollBack();
            throw new SeguridadException(error, e);
        }


    }


    /**
     * Devuelve un {@link Agrupacion} nuevo con todos sus par&aacute;metros.
     *
     * @param usuarioSeguridad    que va a pertencer a la {@link Agrupacion}.
     * @param enlaceTransaccional enlace para hacer at&oacute;micas las transacciones.
     *
     * @return un nuevo agrupacion
     *
     * @throws com.psiqueware.alheli.seguridad.SeguridadException en caso de no poder instanciar la agrupacion.
     * @noinspection DuplicateStringLiteralInspection, MethodReturnOfConcreteClass, StaticMethodReferencedViaSubclass
     */
    private AgrupacionK nuevaAgrupacion(final UsuarioSeguridad usuarioSeguridad, final EnlaceTransaccional enlaceTransaccional) throws SeguridadException
    {
        //validamos
        if (null == usuarioSeguridad)
            throw new NullArgumentException("<error>El argumento 'usuarioSeguridad' no puede ser NULL.</error>");
        final CredencialK credencialK = (CredencialK) usuarioSeguridad.getCredencial();
        if (null == credencialK)
            throw new NullArgumentException("<error>El argumento 'credencial' no puede ser NULL.</error>");
        if (null == credencialK.getId())
            throw new IllegalArgumentException("<error>El argumento 'credencial' deb&iacute;a encontrarse previamente persistido.</error>");
        try
        {

            final AgrupacionDAO daoAgrupacion = SeguridadDAOFactory.findDAOAgrupacion(enlaceTransaccional);
            final RolDAO daoRol = SeguridadDAOFactory.findDAORol(enlaceTransaccional);

            //iniciamos
            final RolK rolK = new RolK();
            rolK.setNombre(s_nombre_rol_universal);
            daoRol.saveRol(rolK, enlaceTransaccional);

            final AgrupacionK agrupacionK = new AgrupacionK();
            agrupacionK.addRol(rolK);
            agrupacionK.setIdCredencialUsuarioRaiz(credencialK.getId());
            daoAgrupacion.saveAgrupacion(agrupacionK, enlaceTransaccional);

            rolK.setAgrupacion(agrupacionK);
            daoRol.updateRol(rolK, enlaceTransaccional);

            final RolCredencialK rolCredencialK = new RolCredencialK(rolK, credencialK);
            SeguridadDAOFactory.findDAORolCredencial(enlaceTransaccional).saveRolCredencial(rolCredencialK, enlaceTransaccional);

            final RolesManagerK rolesManager = (RolesManagerK) SeguridadManagerFactory.getRolesManager();
            rolesManager.agregaPermisoSinSeguridad(Rol.PERMISO, rolK, enlaceTransaccional);
            rolesManager.agregaPermisoSinSeguridad(Agrupacion.PERMISO, rolK, enlaceTransaccional);
            rolesManager.agregaPermisoSinSeguridad(Credencial.PERMISO, rolK, enlaceTransaccional);
            rolesManager.agregaPermisoSinSeguridad(UsuariosSeguridadManager.PERMISO, rolK, enlaceTransaccional);

            credencialK.addRolCredencial(rolCredencialK);
            return agrupacionK;
        }
        catch (Exception e)
        {
            String error = "Un error en la Base de Datos no permitir&aacute; el correcto funcionamiento de las Agrupaciones.";
            s_log.fatal(error);
            enlaceTransaccional.rollBack();
            throw new SeguridadException(error, e);
        }
    }

    /**
     * Registra un Usuario en la seguridad. Es decir le carga la credencial con los roles dados de alta.
     * En caso de ser el presidente de la agrupacion le asigna un Rol con todos los permisos del sistema.
     *
     * @param usuarioSeguridad    Implementaci&oacute;n de esta interfaz a la que se le asignar&aacute; un usuario de seguridad.
     *                            Debe tener un identificador &uacute;nico, afin de poder distinguir un {@link UsuarioSeguridad} de otro. En caso de no
     *                            estar inicializado este par&aacute;metr&oacute; surgir&aacute; un {@link IllegalArgumentException}.
     * @param enlaceTransaccional enlace para hacer at&oacute;micas las transacciones.
     *
     * @throws SeguridadException           en caso de no poder completar la operaci&oacute;n.
     * @throws UsuarioNoRegistradoException en caso de que el UsuariosSeguridad que se pretende iniciar no se encuentre registrado.
     * @noinspection FeatureEnvy
     */
    public void iniciarSeguridadUsuario(UsuarioSeguridad usuarioSeguridad, final EnlaceTransaccional enlaceTransaccional)
            throws SeguridadException, UsuarioNoRegistradoException
    {
        try
        {
            if (null == usuarioSeguridad)
                throw new NullArgumentException("<error>El argumento 'usuarioSeguridad' no puede ser NULL.</error>");
            if (null == usuarioSeguridad.getId())
                throw new IllegalArgumentException("<error>El argumento 'usuarioSeguridad' deb&iacute;a encontrarse previamente persistido.</error>");

            //El if es para evitar error y agilizar el registro.
            CredencialK credencial = (CredencialK) usuarioSeguridad.getCredencial();
            if (null == credencial)
            {
                credencial = buscaCredencialUsuario(usuarioSeguridad, enlaceTransaccional);
                usuarioSeguridad.setCredencial(credencial);
            }

            //Verificamos que se haya dado de alta el usuario.
            if (null != credencial)
            {
                //Verificamos que tenga asignado una agrupacion.
                final AgrupacionK agrupacion = (AgrupacionK) credencial.getAgrupacion();
                if (null == agrupacion)
                {
                    String error = "<error><msg>Se encontr&oacute; una credencial que no tiene agrupacionEmpresarial.</msg></error>";
                    s_log.error(error);
                    throw new IllegalStateException(error);
                }
            }
            else
            {
                String error = "<error><msg>El usuario que se intenta registrar no se encontraba dado de alta.</msg></error>";
                s_log.error(error);
                throw new UsuarioNoRegistradoException(error);
            }
        }

        catch (UsuarioNoRegistradoException e)
        {
            String error = "<error><msg>El Usuario no se encontraba Registrado.</msg><parametros>" + usuarioSeguridad + "</parametros></error>";
            s_log.error(error);
            s_log.error(e);
            enlaceTransaccional.rollBack();
            throw new UsuarioNoRegistradoException(error, e);
        }
        catch (Exception e)
        {
            String error = "<error><msg>No se pudo iniciar la seguridad del Usuario.</msg><parametros>" + usuarioSeguridad + "</parametros></error>";
            s_log.error(error);
            s_log.error(e);
            enlaceTransaccional.rollBack();
            throw new SeguridadException(error, e);
        }
    }

    /**
     * A&ntilde;ade un {@link UsuarioSeguridad} a la {@link Agrupacion} de estos.
     * Adem&aacute;s inicializa su credencial sin roles.
     *
     * @param usuarioSeguridad    Implementaci&oacute;n de esta interfaz a la que se le asignar&aacute; un usuario de seguridad.
     *                            Debe tener un identificador &uacute;nico, afin de poder distinguir un {@link UsuarioSeguridad} de otro. En caso de no
     *                            estar inicializado este par&aacute;metr&oacute; surgir&aacute; un {@link IllegalArgumentException}.
     * @param autoriza            {@link UsuarioSeguridad} que tiene los {@link Permiso}s para validar la operaci&oacute;n.
     * @param enlaceTransaccional enlace para hacer at&oacute;micas las transacciones.
     *
     * @throws com.psiqueware.alheli.seguridad.SeguridadException en caso de no poder completar la operaci&oacute;n.
     * @noinspection FeatureEnvy, CastToConcreteClass, OverlyLongMethod
     */
    public void registrarNuevoUsuario(final UsuarioSeguridad usuarioSeguridad, final UsuarioSeguridad autoriza, final EnlaceTransaccional enlaceTransaccional) throws SeguridadException
    {
        try
        {
            if (null == usuarioSeguridad)
                throw new NullArgumentException("<error>El argumento 'usuarioSeguridad' no puede ser NULL.</error>");
            if (null == usuarioSeguridad.getId())
                throw new IllegalArgumentException("<error>El argumento 'usuarioSeguridad' deb&iacute;a encontrarse previamente persistido.</error>");
            if (null != usuarioSeguridad.getCredencial())
                throw new SeguridadException("<error><msg>Este Usuario ya se ten&iacute;a registrado.</msg><parameters>" + usuarioSeguridad + "</parameters></error>");
            if (!autoriza.getCredencial().tienePermiso(Credencial.PERMISO))
                throw new SeguridadException("<error><msg>El usuario autoriza no tiene la autoridad para realizar la operaci&oacute;n..</msg><parameters>" + autoriza + "</parameters></error>");

            //Le creamos una Credencial.
            CredencialK credencialK = nuevaCredencialUsuarioSeguridad(usuarioSeguridad, enlaceTransaccional);
            Agrupacion agrupacion = (AgrupacionK) autoriza.getCredencial().getAgrupacion();
            if (agrupacion == null)
            {
                String error = "<error><msg>El usuario autorizador no tiene un agrupacion dada de alta.</msg><parameters>" + credencialK + "</parameters></error>";
                s_log.error(error);
                throw new IllegalStateException(error);
            }

            credencialK.setAgrupacion(agrupacion);
            usuarioSeguridad.setCredencial(credencialK);

            SeguridadDAOFactory.findDAOAgrupacion(enlaceTransaccional).updateAgrupacion(agrupacion, enlaceTransaccional);
            SeguridadDAOFactory.findDAOCredencial(enlaceTransaccional).updateCredencial(credencialK, enlaceTransaccional);
            //Registramos al usuario.
            iniciarSeguridadUsuario(usuarioSeguridad, enlaceTransaccional);
        }
        catch (UsuarioNoRegistradoException e)
        {
            String error = "<error><msg>El UsuarioSeguridad se intento registrar y no se logro.</msg><parametros>" + usuarioSeguridad + "</parametros></error>";
            s_log.error(error);
            s_log.error(e);
            enlaceTransaccional.rollBack();
            throw new SeguridadException(error, e);
        }
        catch (Exception e)
        {
            String error = "<error><msg>No se pudo registrar el Usuario.</msg><parameters>" + usuarioSeguridad + "</parameters></error>";
            s_log.error(error);
            s_log.error(e);
            enlaceTransaccional.rollBack();
            throw new SeguridadException(error, e);
        }
    }

    /**
     * Elimina un {@link UsuarioSeguridad} de la aplicaci&oacute;n.
     * <br/><b>Consideraciones</b>
     * <br/> Se pueden dar 2 casos:
     * <ul>
     * <li>Se pretende eliminar un usuario normal.- Se elimina la credencial de dicho usuario.</li>
     * <li>Se pretende eliminar un usuario presidente.- Se elimina la credencial de dicho usuario, el agrupacion, todos los roles y credenciales dados de alta para dicho agrupacion.</li>
     * </ul>
     * Si ya no hay id registrados para el {@link Agrupacion} del {@link UsuarioSeguridad}
     * elimina tambien el {@link Agrupacion} y sus respectivos {@link Rol}es.
     *
     * @param enlaceTransaccional enlace para hacer at&oacute;micas las transacciones.
     * @param eliminar            {@link UsuarioSeguridad} a eliminar.
     * @param autoriza            {@link UsuarioSeguridad} que autoriza la transacci&oacute;n.
     *
     * @return <code>true</code> si se elimin&oacute; sin problemas; <code>false</code> en caso contrario.
     *
     * @throws SeguridadException en caso de que el {@link UsuarioSeguridad} no se eliminara correctamente.
     * @noinspection MethodWithMultipleLoops, FeatureEnvy
     */
    public boolean removeUsuario(UsuarioSeguridad eliminar, UsuarioSeguridad autoriza, final EnlaceTransaccional enlaceTransaccional) throws SeguridadException
    {
        try
        {
            //validamos
            if (null == eliminar)
                throw new NullArgumentException("<error>El argumento 'eliminar' no puede ser NULL.</error>");
            if (null == eliminar.getId())
                throw new IllegalArgumentException("<error>El argumento 'eliminar' deb&iacute;a encontrarse previamente persistido.</error>");
            if (null == eliminar.getCredencial()) throw new SeguridadNoInicializadaException();
            if (null == autoriza)
                throw new NullArgumentException("<error>El argumento 'autoriza' no puede ser NULL.</error>");
            if (null == autoriza.getId())
                throw new IllegalArgumentException("<error>El argumento 'autoriza' deb&iacute;a encontrarse previamente persistido.</error>");
            if (null == autoriza.getCredencial()) throw new SeguridadNoInicializadaException();

            final CredencialDAO daoCredencial = SeguridadDAOFactory.findDAOCredencial(enlaceTransaccional);
            final RolCredencialDAO daoRolCredencial = SeguridadDAOFactory.findDAORolCredencial(enlaceTransaccional);

            //lo quitamos.
            boolean salida = false;
            if (autoriza.getCredencial().tienePermiso(Credencial.PERMISO))
            {
                //1.- Obtenemos la informaci&oacute;n a eliminar.
                CredencialK credencial = (CredencialK) eliminar.getCredencial();

                //2.- Le quitamos la credencial al usuario.
                eliminar.setCredencial(null);

                //3.- Verificamos que no haya mas gente de alta en la agrupacion.
                AgrupacionK agrupacion = (AgrupacionK) credencial.getAgrupacion();

                //4.- Si es un super usuario.
                if (credencial.getId().equals(agrupacion.getIdCredencialUsuarioRaiz()))
                {
                    //5.- Eliminamos todas las credenciales
                    final List<Credencial> credenciales = daoCredencial.listCredencialPorAgrupacion(agrupacion, enlaceTransaccional);
                    for (Credencial eliminame : credenciales)
                    {
                        final CredencialK cK = (CredencialK) eliminame;
                        final List<RolCredencial> rolCredenciales = cK.getRolCredencials();
                        for (final RolCredencial rolCredencial : rolCredenciales)
                        {
                            daoRolCredencial.deleteRolCredencial(rolCredencial, enlaceTransaccional);
                        }
                        daoCredencial.deleteCredencial(eliminame, enlaceTransaccional);
                    }
                    //6.-Eliminamos los roles
                    final RolDAO daoRol = SeguridadDAOFactory.findDAORol(enlaceTransaccional);
                    final PermisoRolDAO daoPermisoRol = SeguridadDAOFactory.findDAOPermisoRol(enlaceTransaccional);
                    for (Rol rol : agrupacion.listRoles())
                    {
                        //No podemos eliminar el RolPresidencial.
                        final RolK rolK = (RolK) rol;
                        rolK.setAgrupacion(agrupacion);
                        final List<PermisoRol> permisoRols = rolK.listPermisoRols();
                        for (final PermisoRol permisoRol : permisoRols)
                        {
                            daoPermisoRol.deletePermisoRol(permisoRol, enlaceTransaccional);
                        }
                        daoRol.deleteRol(rol, enlaceTransaccional);
                    }
                    SeguridadDAOFactory.findDAOAgrupacion(enlaceTransaccional).deleteAgrupacion(agrupacion, enlaceTransaccional);
                }
                else
                {
                    //5.- Eliminamos la credencial
                    final CredencialK cK = (CredencialK) credencial;
                    final List<RolCredencial> rolCredenciales = cK.getRolCredencials();
                    for (final RolCredencial rolCredencial : rolCredenciales)
                    {
                        daoRolCredencial.deleteRolCredencial(rolCredencial, enlaceTransaccional);
                    }
                    daoCredencial.deleteCredencial(credencial, enlaceTransaccional);
                }
                //7.- reportamos el &eacute;xito
                salida = true;
            }
            return salida;
        }
        catch (Exception e)
        {
            String error = "<error><msg>Se encontrar&oacute;n problemas de datos.</msg></error>";
            s_log.error(error);
            s_log.error(e);
            enlaceTransaccional.rollBack();
            throw new SeguridadException(error, e);
        }
    }

    /**
     * Busca la {@link Credencial} de un {@link UsuarioSeguridad} en persistencia
     *
     * @param usuarioSeguridad    cuya credencial se busca.
     * @param enlaceTransaccional enlace para hacer at&oacute;micas las transacciones.
     *
     * @return {@link Credencial} en caso de encontrarla; <code>null</code> de otra manera.
     *
     * @throws SeguridadException en caso de un error en persistencia.
     * @noinspection CastToConcreteClass, MethodReturnOfConcreteClass
     */
    private CredencialK buscaCredencialUsuario(UsuarioSeguridad usuarioSeguridad, final EnlaceTransaccional enlaceTransaccional)
            throws SeguridadException
    {
        final AgrupacionDAO daoAgrupacion = SeguridadDAOFactory.findDAOAgrupacion(enlaceTransaccional);
        final RolCredencialDAO daoRolCredencial = SeguridadDAOFactory.findDAORolCredencial(enlaceTransaccional);
        final RolDAO daoRol = SeguridadDAOFactory.findDAORol(enlaceTransaccional);
        final PermisoRolDAO daoPermisoRol = SeguridadDAOFactory.findDAOPermisoRol(enlaceTransaccional);
        final RegistroPermisoDAO daoRegistroPermiso = SeguridadDAOFactory.findDAORegistroPermiso(enlaceTransaccional);

        try
        {//Buscamos la credencial
            final CredencialK credencial = (CredencialK) SeguridadDAOFactory.findDAOCredencial(enlaceTransaccional).findCredencialUsuarioSeguridad(usuarioSeguridad, enlaceTransaccional);
            if (null != credencial)
            {
                //Agrupacion
                final AgrupacionK agrupacion = (AgrupacionK) daoAgrupacion.findAgrupacionPorId(credencial.getIdAgrupacion(), enlaceTransaccional);
                credencial.setAgrupacion(agrupacion);
                final List<Rol> roles = daoRol.listRolPorAgrupacion(agrupacion, enlaceTransaccional);
                for (final Rol rol : roles)
                {
                    final RolK rolK = (RolK) rol;
                    agrupacion.addRol(rol);
                    rolK.setAgrupacion(agrupacion);
                    final List<PermisoRol> permisosRol = daoPermisoRol.listPermisoRolPorRol(rol, enlaceTransaccional);
                    for (final PermisoRol permisoRol : permisosRol)
                    {
                        final PermisoRolK prK = (PermisoRolK) permisoRol;
                        final Long idRegistroPermiso = prK.getIdRegistroPermiso();
                        final RegistroPermiso registroPermiso = daoRegistroPermiso.findRegistroPermisoPorId(idRegistroPermiso, enlaceTransaccional);
                        prK.setRol(rol);
                        prK.setRegistroPermiso(registroPermiso);
                        rolK.addPermisoRol(prK);
                    }
                }

                //Roles y permisos
                final List<RolCredencial> rolesCredencial = daoRolCredencial.listRolCredencialPorIdCredencial(credencial.getId(), enlaceTransaccional);
                for (final RolCredencial rolCredencial : rolesCredencial)
                {
                    final RolCredencialK rcK = (RolCredencialK) rolCredencial;
                    for (final Rol rol : roles)
                    {
                        if (rol.getId().equals(rcK.getIdRol()))
                        {
                            rcK.setRol(rol);
                            rcK.setCredencial(credencial);
                            break;
                        }
                    }
                    credencial.addRolCredencial(rolCredencial);
                }
            }
            return credencial;
        }
        catch (Exception e)
        {
            String error = "<error><msg>No se pudo definir la CredencialK para el UsuarioSeguridad</msg><parameters>" + usuarioSeguridad + "</parameters></error>";
            s_log.error(error);
            s_log.error(usuarioSeguridad);
            enlaceTransaccional.rollBack();
            throw new SeguridadException(error, e);
        }
    }

    /**
     * Le asigna una nueva {@link Credencial} a un {@link UsuarioSeguridad}
     *
     * @param usuarioSeguridad    cuya credencial se busca.
     * @param enlaceTransaccional enlace para hacer at&oacute;micas las transacciones.
     *
     * @return CredencialK nueva y persistida.
     *
     * @throws SeguridadException en caso de no poder completar la operaci&oacute;n.
     * @noinspection MethodReturnOfConcreteClass
     */
    private CredencialK nuevaCredencialUsuarioSeguridad(UsuarioSeguridad usuarioSeguridad, final EnlaceTransaccional enlaceTransaccional)
            throws SeguridadException
    {
        CredencialK credencialK = null;
        try
        {
            credencialK = new CredencialK(usuarioSeguridad);
            final CredencialDAO daoCredencial = SeguridadDAOFactory.findDAOCredencial(enlaceTransaccional);
            daoCredencial.saveCredencial(credencialK, enlaceTransaccional);
        }
        catch (Exception e)
        {
            String error = "<error><msg>Hubo un problema tratando de Persistir la CredencialK.</msg><parameters>" + credencialK + "</parameters></error>";
            s_log.error(error);
            enlaceTransaccional.rollBack();
            throw new SeguridadException(error, e);
        }
        return credencialK;
    }
}

